package com.cyf.pay.wxpay.service.impl;

import com.cyf.activemq.network.bean.MqBusinessOpt;
import com.cyf.activemq.network.bean.MqSendCouponReq;
import com.cyf.activemq.network.bean.MqSendPayOrderReq;
import com.cyf.activemq.service.SendMsgService;
import com.cyf.db.bean.ad.AdPayOrder;
import com.cyf.db.bean.PayOrder;
import com.cyf.db.mapper.ad.AdPayOrderMapper;
import com.cyf.db.mapper.PayOrderMapper;
import com.cyf.pay.wxpay.bean.*;
import com.cyf.pay.wxpay.service.WxpayService;
import com.cyf.service.AdPayOrderService;
import com.cyf.util.*;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.InputStreamEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;

/**
 * 微信支付接口实现类
 * Created by cage on 2017/2/22.
 */
@Service
public class WxpayServiceImpl implements WxpayService {

    private static final Logger logger = LoggerFactory.getLogger(WxpayServiceImpl.class);
    private static final SimpleDateFormat TIME_END_FORMAT = new SimpleDateFormat("yyyyMMddHHmmss");
    private static final SimpleDateFormat OUTTIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Autowired
    private PayOrderMapper payOrderMapper;
    @Autowired
    private AdPayOrderMapper adPayOrderMapper;
    @Autowired
    private AdPayOrderService adPayOrderService;
    @Autowired
    private SendMsgService sendMsgService;
    @Override
    public WxpayUnifiedOrderRsp unifiedOrder(WxpayUnifiedOrderReq req) {
        try {
            Date date = new Date();
            req.setTime_start(DateUtil.formatDate(date, "yyyyMMddHHmmss"));
            req.setTime_expire(DateUtil.formatDate(DateUtil.getDateAfterSeconds(date, 30 * 60), "yyyyMMddHHmmss"));
            req.setNonce_str(WxpayCore.nonce_str(64));
            req.setSign(WxpayCore.sign(SignUtil.bean2TreeMap(req)));
            String tempXmlStr = XmlUtil.beanToXml(new ByteArrayOutputStream(), req);
            String requestXml = tempXmlStr != null ? tempXmlStr.substring(55) : "";
            logger.info("请求微信内容:" + requestXml);
            InputStreamEntity inputStreamEntity = new InputStreamEntity(
                    new ByteArrayInputStream(requestXml.getBytes("UTF-8")), ContentType.APPLICATION_XML);
            String resultXml = HttpsUtil.post(WxpayConfig.UNIFIEDORDER_URL, inputStreamEntity);
            logger.info("微信返回内容:" + resultXml);
            return resultXml != null
                    ? XmlUtil.xmlToBean(resultXml, WxpayUnifiedOrderRsp.class)
                    : new WxpayUnifiedOrderRsp(WxpayUnifiedOrderRsp.FAIL);
        } catch (Exception e) {
            return new WxpayUnifiedOrderRsp(WxpayUnifiedOrderRsp.FAIL);
        }
    }

    @Override
    public PreparedPayReq getPreparedPayReq(WxpayUnifiedOrderRsp wxpayUnifiedOrderRsp) {
        PreparedPayReq preparedPayReq = new PreparedPayReq();
        preparedPayReq.setAppid(wxpayUnifiedOrderRsp.getAppid());
        preparedPayReq.setPartnerid(wxpayUnifiedOrderRsp.getMch_id());
        preparedPayReq.setPrepayid(wxpayUnifiedOrderRsp.getPrepay_id());
        preparedPayReq.setPackageStr(WxpayConfig.PACKAGESTR);
        preparedPayReq.setNoncestr(WxpayCore.nonce_str(64));
        preparedPayReq.setTimestamp(String.valueOf(System.currentTimeMillis() / 1000));
        preparedPayReq.setSign(WxpayCore.sign(SignUtil.bean2TreeMap(preparedPayReq)));
        return preparedPayReq;
    }

    @Override
    public WxpayNotifyRsp payNotify(WxpayNotifyReq req) {
        WxpayNotifyRsp rsp = new WxpayNotifyRsp();
        rsp.setReturn_code(WxpayNotifyRsp.FAIL);
        try {
            if (req == null) {
                rsp.setReturn_msg("解析参数格式失败");
                return rsp;
            }
            logger.info("微信通知：{}", req.toString());
            String sign = WxpayCore.sign(SignUtil.bean2TreeMap(req));
            boolean ischeck = sign.equals(req.getSign());
            logger.info("微信验签结果:" + ischeck);
            if (!ischeck) {
                rsp.setReturn_msg("验签失败");
                return rsp;
            }

            if (WxpayNotifyReq.SUCCESS.equals(req.getReturn_code())) {
                if ("支付广告费".equals(req.getAttach())) {
                    return payNotifyForAdFee(req);
                } else {
                    return payNotifyForParkingFee(req);
                }

            } else {
                rsp.setReturn_msg("失败");
            }
        } catch (Exception e) {
            logger.error("处理微信支付结果通知异常：{}", e);
            rsp.setReturn_msg("失败");
        }
        return rsp;
    }

    @Override
    public WxpayNotifyRsp monthlyPayNotify(WxpayNotifyReq req) {
        WxpayNotifyRsp rsp = new WxpayNotifyRsp();
        rsp.setReturn_code(WxpayNotifyRsp.FAIL);
        try {
            if (req == null) {
                rsp.setReturn_msg("解析参数格式失败");
                return rsp;
            }
            logger.info("微信通知：{}", req.toString());
            String sign = WxpayCore.sign(SignUtil.bean2TreeMap(req));
            boolean ischeck = sign.equals(req.getSign());
            logger.info("微信验签结果:" + ischeck);
            if (!ischeck) {
                rsp.setReturn_msg("验签失败");
                return rsp;
            }

            if (WxpayNotifyReq.SUCCESS.equals(req.getReturn_code())) {
                return monthlyPayNotifyForParkingFee(req);

            } else {
                rsp.setReturn_msg("失败");
            }
        } catch (Exception e) {
            logger.error("处理微信支付结果通知异常：{}", e);
            rsp.setReturn_msg("失败");
        }
        return rsp;
    }


    private WxpayNotifyRsp monthlyPayNotifyForParkingFee(WxpayNotifyReq req) throws ParseException {
        WxpayNotifyRsp rsp = new WxpayNotifyRsp();
        rsp.setReturn_code(WxpayNotifyRsp.FAIL);
        String orderNo = req.getOut_trade_no();
        PayOrder payOrder = payOrderMapper.getByOrderNo(orderNo);
        if (payOrder == null) {
            rsp.setReturn_msg("商户订单号错误");
            return rsp;
        }
        // 处理重复的通知（微信可能会多次发送同样的通知给商户系统）
        if (PayOrder.PAY_UNKNOWN != payOrder.getPayStatus()) {
            logger.info("该订单已经处理过，不再处理！");
            rsp.setReturn_code(WxpayNotifyRsp.SUCCESS);
        } else {
            int payStatus = WxpayNotifyReq.SUCCESS.equals(req.getResult_code()) ? PayOrder.PAY_SUCCESS : PayOrder.PAY_FAIL;
            // 更新支付账单。
            payOrder.setTransactionId(req.getTransaction_id());
            payOrder.setOpenid(req.getOpenid());
            payOrder.setPayStatus(payStatus);
            payOrder.setPayTime(TIME_END_FORMAT.parse(req.getTime_end()));
            payOrder.setActualFee(req.getCash_fee());
            payOrderMapper.updatePayOrder(payOrder);
            try {
                // 将支付消息添加到消息队列中
                MqSendPayOrderReq mqSendPayOrderReq = new MqSendPayOrderReq();
                BeanUtils.copyProperties(payOrder, mqSendPayOrderReq);
                String uuid = UUID.randomUUID().toString();
                mqSendPayOrderReq.setUuid(uuid);
                mqSendPayOrderReq.setOptid(MqBusinessOpt.CARRECHARGE);
                sendMsgService.sendQueueMessageText(ObjectMapperUtils.getObjectMapper().writeValueAsString(mqSendPayOrderReq));
            } catch (Exception e) {
                e.printStackTrace();
            }


            rsp.setReturn_code(WxpayNotifyRsp.SUCCESS);
        }
        return rsp;
    }
    private WxpayNotifyRsp payNotifyForParkingFee(WxpayNotifyReq req) throws ParseException {
        WxpayNotifyRsp rsp = new WxpayNotifyRsp();
        rsp.setReturn_code(WxpayNotifyRsp.FAIL);
        String orderNo = req.getOut_trade_no();
        PayOrder payOrder = payOrderMapper.getByOrderNo(orderNo);
        if (payOrder == null) {
            rsp.setReturn_msg("商户订单号错误");
            return rsp;
        }
        // 处理重复的通知（微信可能会多次发送同样的通知给商户系统）
        if (PayOrder.PAY_UNKNOWN != payOrder.getPayStatus()) {
            logger.info("该订单已经处理过，不再处理！");
            rsp.setReturn_code(WxpayNotifyRsp.SUCCESS);
        } else {
            int payStatus = WxpayNotifyReq.SUCCESS.equals(req.getResult_code()) ? PayOrder.PAY_SUCCESS : PayOrder.PAY_FAIL;
            // 更新支付账单。
            payOrder.setTransactionId(req.getTransaction_id());
            payOrder.setOpenid(req.getOpenid());
            payOrder.setPayStatus(payStatus);
            payOrder.setPayTime(TIME_END_FORMAT.parse(req.getTime_end()));
            payOrder.setActualFee(req.getCash_fee());
            payOrderMapper.updatePayOrder(payOrder);
            if (1 == payOrder.getFeeType() || 2 == payOrder.getFeeType()) { // 是支付停车费

                // 将支付消息添加到消息队列中
                PayOrderMessageList.addPayOrderMessage(payOrder);
            }
            rsp.setReturn_code(WxpayNotifyRsp.SUCCESS);
        }
        return rsp;
    }

    private WxpayNotifyRsp payNotifyForAdFee(WxpayNotifyReq req) throws ParseException {
        WxpayNotifyRsp rsp = new WxpayNotifyRsp();
        rsp.setReturn_code(WxpayNotifyRsp.FAIL);
        String orderNo = req.getOut_trade_no();
        AdPayOrder adPayOrder = adPayOrderMapper.getByOrderNo(orderNo);
        if (adPayOrder == null) {
            rsp.setReturn_msg("商户订单号错误");
            return rsp;
        }
        // 处理重复的通知（微信可能会多次发送同样的通知给商户系统）
        if (AdPayOrder.STATUS_WAIT_PAY != adPayOrder.getStatus()) {
            logger.info("该订单已经处理过，不再处理！订单状态：{}", adPayOrder.getStatus());
            rsp.setReturn_code(WxpayNotifyRsp.SUCCESS);
        } else {
            if (WxpayNotifyReq.SUCCESS.equals(req.getResult_code())) {
                adPayOrderService.payFinish(adPayOrder, AdPayOrder.STATUS_WAIT_REVIEW, req.getTransaction_id(), req.getTotal_fee(), TIME_END_FORMAT.parse(req.getTime_end()));
            } else {
//                adPayOrderService.payFinish(adPayOrder, 0, req.getTransaction_id(), req.getTotal_fee(), new Date());
            }
            rsp.setReturn_code(WxpayNotifyRsp.SUCCESS);
        }
        return rsp;
    }

    @Override
    public WxpayQueryOrderRsp queryOrder(WxpayQueryOrderReq req) {
        try {
            if (StringUtils.isEmpty(req.getTransaction_id()) && StringUtils.isEmpty(req.getOut_trade_no())) {
                return new WxpayQueryOrderRsp(WxpayUnifiedOrderRsp.FAIL);
            }
            req.setAppid(WxpayConfig.APP_ID);
            req.setMch_id(WxpayConfig.MCH_ID);
            req.setNonce_str(WxpayCore.nonce_str(64));
            req.setSign(WxpayCore.sign(SignUtil.bean2TreeMap(req)).toUpperCase());
            String tempXmlStr = XmlUtil.beanToXml(new ByteArrayOutputStream(), req);
            String requestXml = tempXmlStr != null ? tempXmlStr.substring(55) : "";
            InputStreamEntity inputStreamEntity = new InputStreamEntity(
                    new ByteArrayInputStream(requestXml.getBytes("UTF-8")), ContentType.APPLICATION_XML);
            String resultXml = HttpsUtil.post(WxpayConfig.ORDERQUERY_URL, inputStreamEntity);
            logger.debug("微信返回内容:" + resultXml);
            return resultXml != null
                    ? XmlUtil.xmlToBean(resultXml, WxpayQueryOrderRsp.class)
                    : new WxpayQueryOrderRsp(WxpayUnifiedOrderRsp.FAIL);
        } catch (Exception e) {
            return new WxpayQueryOrderRsp(WxpayUnifiedOrderRsp.FAIL);
        }
    }

    @Override
    public WxpayUnifiedOrderRsp getQrcode(String orderNo, int fee, String reqIp, String subject) {
        WxpayUnifiedOrderReq unifiedOrder = new WxpayUnifiedOrderReq(WxpayConfig.APP_ID, WxpayConfig.MCH_ID, WxpayConfig.NOTIFY_PAY, WxpayConfig.TRADE_TYPE_NATIVE);
        unifiedOrder.setBody(subject);
        unifiedOrder.setOut_trade_no(orderNo);
        unifiedOrder.setTotal_fee(fee);
        unifiedOrder.setSpbill_create_ip(reqIp);
        unifiedOrder.setAttach(subject);
        return unifiedOrder(unifiedOrder);
    }

    @Override
    public WxpayCloseOrderRsp closeOrder(String orderNo) {
        WxpayCloseOrderReq req = new WxpayCloseOrderReq();
        try {
            req.setOut_trade_no(orderNo);
            req.setAppid(WxpayConfig.APP_ID);
            req.setMch_id(WxpayConfig.MCH_ID);
            req.setNonce_str(WxpayCore.nonce_str(64));
            req.setSign(WxpayCore.sign(SignUtil.bean2TreeMap(req)).toUpperCase());
            String tempXmlStr = XmlUtil.beanToXml(new ByteArrayOutputStream(), req);
            String requestXml = tempXmlStr != null ? tempXmlStr.substring(55) : "";
            InputStreamEntity inputStreamEntity = new InputStreamEntity(
                    new ByteArrayInputStream(requestXml.getBytes("UTF-8")), ContentType.APPLICATION_XML);
            String resultXml = HttpsUtil.post(WxpayConfig.CLOSEORDER_URL, inputStreamEntity);
            logger.debug("微信关闭订单返回内容:" + resultXml);
            return resultXml != null
                    ? XmlUtil.xmlToBean(resultXml, WxpayCloseOrderRsp.class)
                    : new WxpayCloseOrderRsp(WxpayCloseOrderRsp.FAIL);
        } catch (Exception e) {
            return new WxpayCloseOrderRsp(WxpayCloseOrderRsp.FAIL);
        }
    }
}
